from fastapi import Request, HTTPException
from fastapi.exceptions import RequestValidationError
from loguru import logger
from starlette import status
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from starlette.responses import Response, JSONResponse
from starlette.types import ASGIApp

from app.core.custom_exception import CustomException
from app.schemas.result_schema import ResultModelBase


class ExceptionHandlerMiddleware(BaseHTTPMiddleware):
    def __init__(self, app: ASGIApp) -> None:
        super().__init__(app)

    async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
        try:
            return await call_next(request)
        except CustomException as e:
            logger.error(
                f"{e.__class__.__name__}: {str(e)}",
                exc_info=True,
                extra={"request": {"method": request.method, "url": str(request.url)}}
            )
            return self.set_result(status_code=e.status_code, message=e.message)
        except HTTPException as e:
            logger.error(
                f"{e.__class__.__name__}: {str(e)}",
                exc_info=True,
                extra={"request": {"method": request.method, "url": str(request.url)}}
            )
            return self.set_result(status_code=e.status_code, message=e.detail)
        except RequestValidationError as e:
            logger.error(
                f"Unexpected Exception: {str(e)}",
                exc_info=True,
                extra={"request": {"method": request.method, "url": str(request.url)}}
            )
            message = e.errors()[0].get("msg")
            if message == "field required":
                message = "请求失败，缺少必填项！"
            elif message == "value is not a valid list":
                message = f"类型错误，提交参数应该为列表！"
            elif message == "value is not a valid int":
                message = f"类型错误，提交参数应该为整数！"
            elif message == "value could not be parsed to a boolean":
                message = f"类型错误，提交参数应该为布尔值！"
            elif message == "Input should be a valid list":
                message = f"类型错误，输入应该是一个有效的列表！"
            return self.set_result(status_code=status.HTTP_400_BAD_REQUEST, message=message)
        except ValueError as e:
            logger.error(
                f"Unexpected Exception: {str(e)}",
                exc_info=True,
                extra={"request": {"method": request.method, "url": str(request.url)}}
            )
            return self.set_result(status_code=status.HTTP_400_BAD_REQUEST, message=e.__str__())
        except Exception as e:
            message = f"服务器内部错误: {str(e)}"
            logger.exception(message, exc_info=True, extra={"request": {"method": request.method, "url": str(request.url)}})
            return self.set_result(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,message=message)

    @staticmethod
    def set_result(status_code: int, message:str)->JSONResponse:
        status_code = status_code or status.HTTP_500_INTERNAL_SERVER_ERROR
        message = message or "系统错误，请联系管理员或稍后再试！"
        result = ResultModelBase(is_success=False, message=message, code=status_code)
        return JSONResponse(content=result.model_dump(), status_code=status_code)

